package mre;

import java.util.Hashtable;
import java.util.LinkedList;

import planninglanguage.conditions.AndCondition;
import planninglanguage.conditions.BuildingCompleteCondition;
import planninglanguage.conditions.Condition;
import planninglanguage.conditions.NotCondition;
import planninglanguage.conditions.NumberOfUnitsOfTypeCondition;
import planninglanguage.conditions.OrCondition;
import planninglanguage.conditions.PlayerExistsCondition;
import planninglanguage.conditions.ResearchCondition;
import planninglanguage.conditions.StatusCondition;
import planninglanguage.conditions.UnitAtCondition;
import planninglanguage.conditions.UnitExistsCondition;
import planninglanguage.conditions.UnitTypeAtCondition;
import planninglanguage.conditions.UnitTypeExistsCondition;
import planninglanguage.goals.Goal;
import planninglanguage.plans.MultiPlan;
import planninglanguage.plans.Plan;
import planninglanguage.plans.SubGoalPlan;
import base.WargusGameState;

public class ConditionGraph {
 
	Plan m_p;
	int cc;
	public ConditionGraph(Plan l_p)
	{
		m_p=l_p;
	}
	
	public void CreateGraph(Goal l_goal, WargusGameState l_gamestate)
	{
		if(m_p instanceof MultiPlan)
		{
			Condition successCondition = l_goal.generateSuccessCondition(l_gamestate);
			
			LinkedList<ConditionTruth> conditions = getConditions(successCondition);
			if(m_p.getPostCondition()!=null)
			{
				conditions= appendList(conditions,getConditions(m_p.getPostCondition()));
			}
			
			if(!subGoalsPresent((MultiPlan) m_p))
			{
				LinkedList<Plan> BOPlans = getAllBOPlans(m_p);
				for(int i=0;i<BOPlans.size();i++)
					BOPlans.get(i).setInActive();
				LinkedList<Plan> temp =new LinkedList<Plan>();
				getDependencies(temp, (MultiPlan) m_p, conditions,l_gamestate);
				System.out.println(temp.size());
				for(int i=0;i<BOPlans.size();i++)
					System.out.println(BOPlans.get(i).getActive());
			}
			
			}
		}
	
	public void getDependencies(LinkedList<Plan> BOPlan, MultiPlan mp, 
			LinkedList<ConditionTruth> conditions,WargusGameState l_gamestate)
	{
		LinkedList<Plan> directPlans = new LinkedList<Plan>();
		for(Plan p : mp)
		{
			if(!(p instanceof MultiPlan))
			{
			LinkedList<ConditionTruth> success_condition1 = getConditions(getPlanSuccessCondition(p,l_gamestate));
			if(p.getPostCondition()!=null)
			{
				success_condition1= appendList(success_condition1,getConditions(p.getPostCondition()));
			}
				boolean isLink =isCommon(success_condition1,conditions,l_gamestate);
				if(isLink==true)
					directPlans.add(p);
			}
		}
		for(Plan p : mp) {
			if(p instanceof MultiPlan) {
				getDependencies((LinkedList<Plan>)BOPlan.clone(), (MultiPlan) p,
						conditions,l_gamestate);
			} else {
				prePlans(p,BOPlan,l_gamestate);
				BOPlan.addAll(getAllBOPlans(p)); // XXX was only on sequential before.. merged to MultiPlan
			}
		}
		setActivePlans(directPlans,l_gamestate);
	}
	
	public void prePlans(Plan p,LinkedList<Plan> l_subPlans,WargusGameState l_gamestate)
	{
		LinkedList<ConditionTruth> pre_condition1 = getConditions(p.getPreCondition());
		LinkedList<ConditionTruth> alive_Condition= getConditions(p.getAliveCondition());
		pre_condition1=appendList(pre_condition1,alive_Condition);
		if(p.getHiddenCondition()!=null)
		pre_condition1=appendList(pre_condition1,getConditions(p.getHiddenCondition()));
		for(int j=0;j<l_subPlans.size();j++)
		{
		
			Plan p2 = l_subPlans.get(j);
			LinkedList<ConditionTruth> success_condition2= getConditions(getPlanSuccessCondition(p2,l_gamestate));
			if(p2.getPostCondition()!=null)
			{
				success_condition2= appendList(success_condition2,getConditions(p2.getPostCondition()));
			}
			
			boolean isLink =isCommon(success_condition2,pre_condition1,l_gamestate);
			LinkedList<Plan> l_prePlans = p.getPrePlans();
			if(isLink==true)
			{
				l_prePlans.add(p2);
				p.setPrePlans(l_prePlans);
			}
		}
	}
	
	public LinkedList<Plan> getAllBOPlans(Plan plan)
	{
		LinkedList<Plan> BOPlans = new LinkedList<Plan>();
		if(plan instanceof MultiPlan) {
			for(Plan p : (MultiPlan) plan) {
				BOPlans.addAll(getAllBOPlans(p));
			}
		} else {
			BOPlans.add(plan);
		}
		return BOPlans;
	}
	
	public boolean subGoalsPresent(MultiPlan plans)
	{
		for(Plan l_p : plans)
		{
			String className = l_p.getClass().getSimpleName(); 
			if(className.equals("SubGoalPlan"))
				return true;
			if (l_p instanceof MultiPlan) {
				MultiPlan l_multiPlan = (MultiPlan)l_p;
				if(subGoalsPresent(l_multiPlan))
					return true;
			}
		}
		return false;
	}
	 
	public Hashtable storePlans(LinkedList<Plan> plans)
	{
		Hashtable storedPlans = new Hashtable();
		for(int i=0;i<plans.size();i++)
		{
			Plan p = plans.get(i);
			if(!p.getActive())
			{
				LinkedList <ConditionTruth> conditions = getConditions(p.getSuccessCondition());
				conditions =appendList(conditions,getConditions(p.getPostCondition()));
			}
		}
		return storedPlans;
	}
	
	public void setActivePlans(LinkedList<Plan> plans,WargusGameState l_gameState)
	{
		for(int i=0;i<plans.size();i++)
		{
			Plan p = plans.get(i);
			if(!p.getSuccessCondition().test(l_gameState))
				p.setActive();
			setActivePlans(p.getPrePlans(),l_gameState);
		}
		
	}
	
	public Condition getPlanSuccessCondition(Plan p, WargusGameState l_gamestate)
	{
		Condition l_c1 = p.getSuccessCondition();
		
		if (p instanceof SubGoalPlan) {
			l_c1 = ((SubGoalPlan)p).getGoal().generateSuccessCondition(l_gamestate);
		} else if(p instanceof MultiPlan) {
			l_c1 = ((MultiPlan)p).getStateSuccessCondition(l_gamestate);
		}
		return l_c1;
	}
	public boolean isCommon(LinkedList<ConditionTruth> l1,LinkedList<ConditionTruth> l2,WargusGameState gamestate)
	{
		boolean common=false;
		for(int i=0;i<l1.size();i++)
		{
			
			Condition c1 =l1.get(i).getConditon();
			String className1 = c1.getClass().getSimpleName();
			for(int j=0;j<l2.size();j++)
			{
				Condition c2 =l2.get(j).getConditon();
				String className2 = c2.getClass().getSimpleName();
				if(className1.equals(className2))
				{
					common =true;
					if(className1.equals("BuildingCompleteCondition"))
						common = ((BuildingCompleteCondition)c1).compare((BuildingCompleteCondition)c2);
					if(className1.equals("NumberOfUnitsOfTypeCondition"))
						common = ((NumberOfUnitsOfTypeCondition)c1).compare((NumberOfUnitsOfTypeCondition)c2);
					if(className1.equals("PlayerExistsCondition"))
						common = ((PlayerExistsCondition)c1).compare((PlayerExistsCondition)c2);
					if(className1.equals("ResearchCondition"))
						common = ((ResearchCondition)c1).compare((ResearchCondition)c2);
					if(className1.equals("StatusCondition"))
						common = ((StatusCondition)c1).compare((StatusCondition)c2);
					if(className1.equals("UnitAtCondition"))
						common = ((UnitAtCondition)c1).compare((UnitAtCondition)c2);
					if(className1.equals("UnitExistsCondition"))
						common = ((UnitExistsCondition)c1).compare((UnitExistsCondition)c2);
					if(className1.equals("UnitTypeAtCondition"))
						common = ((UnitTypeAtCondition)c1).compare((UnitTypeAtCondition)c2);
					if(className1.equals("UnitTypeExistsCondition"))
						common = ((UnitTypeExistsCondition)c1).compare((UnitTypeExistsCondition)c2);
					
				}
				else 
				if(className1.equals("StatusCondition") && (className2.equals("WoodCondition")||className2.equals("GoldCondition")||className2.equals("OilCondition")))
						{
							StatusCondition sc = (StatusCondition)c1;
							if(sc.getStatus().equals("resource"))
							{
								common=true;
							}
						}
				else if(className2.equals("StatusCondition") && (className1.equals("WoodCondition")||className1.equals("GoldCondition")||className1.equals("OilCondition")))
				{
					StatusCondition sc = (StatusCondition)c2;
					if(sc.getStatus().equals("resource"))
					{
						common=true;
					}
				}
				else
				{
					String u1 = getUnitType(c1,gamestate);
					String u2 = getUnitType(c2,gamestate);
					if(u1.length()>0 && u1.equals(u2))
						common = true;
				}
			}
		}
		return common;
	}
	
	public String getUnitType(Condition c,WargusGameState gamestate)
	{
		String unitType ="";
		if(c.getClass().getSimpleName().equals("NumberOfUnitsOfTypeCondition"))
			unitType = ((NumberOfUnitsOfTypeCondition)c).getUnitType();
		if(c.getClass().getSimpleName().equals("UnitTypeAtCondition"))
			unitType = ((UnitTypeAtCondition)c).getUnitType();
		if(c.getClass().getSimpleName().equals("UnitTypeExistsCondition"))
			unitType = ((UnitTypeExistsCondition)c).getUnitType();
		if(c.getClass().getSimpleName().equals("UnitAtCondition"))
			unitType = ((UnitAtCondition)c).getUnitType(gamestate);
		if(c.getClass().getSimpleName().equals("BuildingCompleteCondition"))
			unitType = ((BuildingCompleteCondition)c).getUnitType();
		if(c.getClass().getSimpleName().equals("UnitExistsCondition"))
		{
			unitType = ((UnitExistsCondition)c).getUnitType(gamestate);
		}
		return unitType ;
		
	}
	LinkedList<ConditionTruth> appendList(LinkedList<ConditionTruth> list1, LinkedList<ConditionTruth> list2)
	{
		for(int i=0;i<list2.size();i++)
			list1.add(list2.get(i));
		return list1;
	}
	public LinkedList<ConditionTruth> getConditions(Condition c)
	{
		LinkedList<ConditionTruth> conditions = new LinkedList<ConditionTruth>();
		String conditionType = c.getClass().getSimpleName();
		if(conditionType.equals("AndCondition"))
		{
			conditions = appendList(conditions,getConditions(((AndCondition)c).getC1()));
			conditions = appendList(conditions,getConditions(((AndCondition)c).getC2()));
		}
		else if(conditionType.equals("OrCondition"))
		{
			conditions = appendList(conditions,getConditions(((OrCondition)c).getC1()));
			conditions = appendList(conditions,getConditions(((OrCondition)c).getC2()));
		}
		else if(conditionType.equals("NotCondition"))
		{
			conditions.add(new ConditionTruth(((NotCondition)c).getCondition(),false));
		}
		else
			conditions.add(new ConditionTruth(c,true));
		return conditions;
	}
}

class ConditionTruth
{
	Condition m_c;
	boolean m_truth;
	public ConditionTruth(Condition l_c, boolean l_truth)
	{
		m_c=l_c;
		m_truth =l_truth;
	}
	
	public Condition getConditon()
	{
		return m_c;
	}
	
	public boolean getTruth()
	{
		return m_truth;
	}
}
